package com.zhoug.player.vlcplayer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.view.Surface;
import android.view.TextureView;

import com.zhoug.player.core.CapturePictureListener;
import com.zhoug.player.core.PlayError;
import com.zhoug.player.core.PlayProgressListener;
import com.zhoug.player.core.VideoRecordListener;
import com.zhoug.player.core.utils.LogUtils;
import com.zhoug.player.core.utils.ThreadUtils;
import com.zhoug.player.core.utils.Utils;

import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import org.videolan.libvlc.interfaces.IVLCVout;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Locale;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author: zhoug
 * @since: 2025-08-11
 */
public class VLCPlayer2 implements IPlayer6 {
    private static final String TAG = ">>>VLCPlayer2";
    private static final TimePrinter TIME_PRINTER = new TimePrinter();
    // 操作意图常量
    private static final int OP_NONE = 0;//没有任何操作
    private static final int OP_INIT_LIB = 1;//初始化lib
    private static final int OP_CREATE_PLAYER = 2;//创建播放器
    private static final int OP_PLAY = 3;//播放
    private static final int OP_PAUSE = 4;//暂停
    private static final int OP_STOP = 5;//停止
    private static final int OP_RELEASE = 8;//释放资源
    private volatile int mCurrentOption = OP_NONE;//当前的意图操作
    private volatile int currentState = IDLE;//播放器状态



    private static int STATE_IDLE=0;
    private static int STATE_PLAYING=0;
    private static int STATE_STOPPED=0;
    private static int STATE_ENDED=0;


    /**
     * 每500毫秒更新一次播放进度
     */
    private static final long PROGRESS_UPDATE_INTERVAL = 500;
    private final Context context;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private HandlerThread backgroundThread;
    private Handler backgroundHandler;
    private LibVLC libVLC;
    private MediaPlayer mediaPlayer;
    private String mPlayUrl;

    // Listeners
    private Listener playListener;
    private CapturePictureListener capturePictureListener;
    private VideoRecordListener videoRecordListener;
    private PlayProgressListener playProgressListener;

    private TextureView textureView;
    private boolean mute = false;
    private String recordPath;
    private volatile boolean isRecording;
    private boolean isRelease = false;


    public VLCPlayer2(Context context,int num){
        this.context = context.getApplicationContext();
        TIME_PRINTER.start("开始初始化播放器");
        for (int i = 0; i < num; i++) {
            ArrayList<String> options = new OptionsBuilder().build();
            LibVLC libVLC = new LibVLC(context, options);
            MediaPlayer mediaPlayer = new MediaPlayer(libVLC);
        }
        TIME_PRINTER.print("初始化播放器");
    }

    public VLCPlayer2(Context context) {
        this.context = context.getApplicationContext();
        initBackgroundThread();
    }

    /**
     * 初始化后台线程
     */
    private void initBackgroundThread() {
        backgroundThread = new HandlerThread("VLC-PlayerThread");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case OP_INIT_LIB://初始化播放器
                        LogUtils.d(TAG, "handleMessage:OP_INIT_LIB");
                        if (mCurrentOption != OP_RELEASE) {
                            _initVLC();
                        }
                        break;
                    case OP_CREATE_PLAYER://创建播放器
                        LogUtils.d(TAG, "handleMessage:OP_CREATE_PLAYER");
                        if (libVLC != null && mCurrentOption != OP_RELEASE) {
                            _createMediaPlayer();
                        }
                        break;
                    case OP_PLAY://开始播放
                        LogUtils.d(TAG, "handleMessage:OP_PLAY");
                        if (mCurrentOption == OP_PLAY) {
                            _play();
                        }

                        break;
                    case OP_PAUSE://暂停
                        LogUtils.d(TAG, "handleMessage:OP_PAUSE");
                        if (mCurrentOption == OP_PAUSE) {
                            _pause();
                        }
                        break;
                    case OP_STOP://停止
                        LogUtils.d(TAG, "handleMessage:OP_STOP");
                        if (mCurrentOption == OP_STOP) {
                            _stop();
                        }
                        break;
                    case OP_RELEASE://释放资源
                        LogUtils.d(TAG, "handleMessage:OP_RELEASE");
                        if (mCurrentOption == OP_RELEASE) {
                            _release();
                        }
                        break;

                }
            }
        };
        if (libVLC == null) {
            sendOption(OP_INIT_LIB);
        }
        sendOption(OP_CREATE_PLAYER);
    }

    /**
     * 发送当前需要执行的操作
     *
     * @param option
     */
    private synchronized void sendOption(int option) {
        if (mCurrentOption != option && mCurrentOption != OP_RELEASE) {
            if (option == OP_RELEASE) {
                //清楚其它全部消息
                backgroundHandler.removeMessages(OP_INIT_LIB);
                backgroundHandler.removeMessages(OP_CREATE_PLAYER);
                backgroundHandler.removeMessages(OP_PLAY);
                backgroundHandler.removeMessages(OP_PAUSE);
                backgroundHandler.removeMessages(OP_STOP);
            }
            Message message = backgroundHandler.obtainMessage();
            mCurrentOption = option;
            message.what = option;
            backgroundHandler.sendMessage(message);
        }

    }

    /**
     * 初始化播放器
     */
    private synchronized void _initVLC() {
        try {
            if (libVLC != null) return;
            ArrayList<String> options = new OptionsBuilder().build();
            TIME_PRINTER.start("开始初始化播放器");
            libVLC = new LibVLC(context, options);
            TIME_PRINTER.print("播放器初始化成功");
        } catch (Exception e) {
//            setState(ERROR);
            notifyError(PlayError.PLAYER_INIT_FAILURE, e.getMessage());
        }
    }

    /**
     * 创建mediaPlayer实例
     */
    private synchronized void _createMediaPlayer() {
        try {
            if (mediaPlayer != null) return;
            if (libVLC == null) {
                LogUtils.e(TAG, "createMediaPlayer:libVLC 未初始化");
                return;
            }
            TIME_PRINTER.start("开始创建mediaPlayer实例");
            mediaPlayer = new MediaPlayer(libVLC);
            TIME_PRINTER.print("创建mediaPlayer实例成功");
            setupMediaPlayerListeners();
            mainHandler.post(this::_bindVideoSurface);
        } catch (Exception e) {
            notifyError(PlayError.PLAYER_INIT_FAILURE, e.getMessage());
        }
    }

    /**
     * 开始播放
     */
    private synchronized void _play() {
        if (mediaPlayer != null && !isPlaying()) {
            try {
                TIME_PRINTER.start("Prepare 准备资源");
                Media media = new Media(libVLC, Uri.parse(mPlayUrl));
//                media.setHWDecoderEnabled(true, false);
                media.setHWDecoderEnabled(false, false);//设置后才可以录制和截屏,这行必须放在mMediaPlayer.setMedia(media)后面，因为setMedia会设置setHWDecoderEnabled为true

                mediaPlayer.setMedia(media);
//                setState(PREPARED);
                //为什么需要release media
                media.release();
                TIME_PRINTER.print("Prepare 准备资源");

                TIME_PRINTER.start("Play 开始播放");
                mediaPlayer.play();
                TIME_PRINTER.print("Play 开始播放");

            } catch (Exception e) {
//                setState(ERROR);
                notifyError(PlayError.MEDIA_ERROR, e.getMessage());
            }


        }

    }

    /**
     * 暂停播放
     */
    private synchronized void _pause() {
        if (mediaPlayer != null && isPlaying()) {
            TIME_PRINTER.start("Pause 暂停播放");
            mediaPlayer.pause();
            TIME_PRINTER.print("Pause 暂停播放");
        }
    }

    /**
     * 停止播放
     */
    private synchronized void _stop() {
        if (mediaPlayer != null) {
            TIME_PRINTER.start("Stop 停止播放");
            mediaPlayer.stop();
            TIME_PRINTER.print("Stop 停止播放");
            stopProgressUpdates();
        }
    }

    /**
     * 释放资源
     * 必须在线程中释放资源,经测试有时需要耗时大10多秒
     */
    private synchronized void _release() {
        TIME_PRINTER.start("Release 开始释放资源");
        stopProgressUpdates();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }

        if (libVLC != null) {
            libVLC.release();
            libVLC = null;
        }
        if (backgroundThread != null) {
            backgroundThread.quitSafely();
            try {
                backgroundThread.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            backgroundThread = null;
            backgroundHandler = null;
        }
        TIME_PRINTER.print("Release 释放资源");
        isRelease = true;
    }


    /**
     * 设置播放监听器
     */
    private void setupMediaPlayerListeners() {
        if (mediaPlayer == null) return;
        mediaPlayer.setEventListener(event -> {
            switch (event.type) {
                case MediaPlayer.Event.MediaChanged://当播放的媒体发生变化时触发。例如，播放列表中的下一个媒体开始播放。
                    LogUtils.d(TAG, "onEvent MediaChanged");
                    break;
                case MediaPlayer.Event.Opening://当媒体开始打开（准备播放）但还未开始播放时触发
                    LogUtils.d(TAG, "onEvent Opening");
                    LogUtils.d(TAG, "onEvent:"+isPlaying());
                    break;
                case MediaPlayer.Event.Buffering://当播放器正在缓冲数据时触发。通常发生在网络流媒体播放时。
                    float buffering = event.getBuffering();
                    LogUtils.d(TAG, "onEvent Buffering:"+buffering);
                    LogUtils.d(TAG, "onEvent:"+isPlaying());

                    if (currentState == PLAYING) {
                        setState(BUFFERING);
                    } else if (buffering >= 100f) {
                        setState(PLAYING);
                    }
                    break;

                case MediaPlayer.Event.Playing://当媒体开始播放（或从暂停状态恢复播放）时触发。
                    LogUtils.d(TAG, "onEvent Playing");
                    LogUtils.d(TAG, "onEvent:"+isPlaying());

                    setState(PLAYING);
                    startProgressUpdates();
                    break;
                case MediaPlayer.Event.Paused://当媒体被暂停时触发
                    LogUtils.d(TAG, "onEvent Paused");
                    LogUtils.d(TAG, "onEvent:"+isPlaying());

                    setState(PAUSED);
                    break;
                case MediaPlayer.Event.Stopped://当媒体停止播放时触发（例如，调用停止方法后）。
                    LogUtils.d(TAG, "onEvent Stopped");
                    LogUtils.d(TAG, "onEvent:"+isPlaying());

                    setState(STOPPED);
                    stopProgressUpdates();
                    break;
                case MediaPlayer.Event.EndReached://当媒体播放到达末尾时触发
                    LogUtils.d(TAG, "onEvent EndReached");
                    LogUtils.d(TAG, "onEvent:"+isPlaying());

                    setState(ENDED);
                    stopProgressUpdates();
                    break;
                case MediaPlayer.Event.EncounteredError://当播放过程中遇到错误时触发。
                    LogUtils.d(TAG, "onEvent EncounteredError");
//                    setState(ERROR);
                    notifyError(PlayError.PLAYING_ENCOUNTERED_ERROR);
                    break;
                case MediaPlayer.Event.Vout://当视频输出（video output）改变时触发。例如，视频轨道变化或者视频输出设备改变。
                    LogUtils.d(TAG, "onEvent Vout");
                    if (event.getVoutCount() > 0) {
                       /* int width = mediaPlayer.getVideoWidth();
                        int height = mediaPlayer.getVideoHeight();
                        if (width > 0 && height > 0 && playListener != null) {
                            mainHandler.post(() -> playListener.onVideoSizeChanged(width, height));
                        }*/
                    }
                    break;
                case MediaPlayer.Event.TimeChanged://当媒体的播放时间（当前位置）改变时触发。这通常发生在播放过程中或者用户拖动进度条后。
//                    LogUtils.d(TAG, "onEvent TimeChanged:"+getCurrentPosition());

                    break;
                case MediaPlayer.Event.LengthChanged://当媒体的总长度改变时触发。这在播放实时流时可能会发生，因为总时长在不断增加。
//                    LogUtils.d(TAG, "onEvent LengthChanged:"+getDuration());

                    break;
//                case MediaPlayer.Event.PositionChanged:// 当媒体的播放位置（百分比）改变时触发。与`TimeChanged`类似，但表示的是相对位置。
//                    LogUtils.d(TAG, "PositionChanged:"+getCurrentPosition());
//                    break;
                case MediaPlayer.Event.SeekableChanged://当媒体的可跳转状态改变时触发。例如，某些直播流开始可能不允许跳转，但之后允许跳转（比如回放）。
                    LogUtils.d(TAG, "onEvent SeekableChanged1:" + isSeekable());
                    LogUtils.d(TAG, "onEvent SeekableChanged2:" + event.getSeekable());


                    break;
                case MediaPlayer.Event.PausableChanged://当媒体的可暂停状态改变时触发。例如，某些直播流可能不允许暂停。
                    LogUtils.d(TAG, "onEvent PausableChanged:" + event.getPausable());
                    break;

               /* case MediaPlayer.Event.ESAdded:// 当新的基本流（Elementary Stream）被添加时触发。基本流是指媒体中的音频、视频或字幕轨道。 例如，一个多音轨的视频在播放过程中动态添加了新的音轨。

                    break;
                case MediaPlayer.Event.ESDeleted:// 当基本流被移除时触发

                    break;
                case MediaPlayer.Event.ESSelected:// 当某个基本流被选中（例如，用户切换了音轨或字幕）时触发。

                    break;*/
                case MediaPlayer.Event.RecordChanged://  当录制状态改变时触发。例如，开始录制或停止录制。
                    LogUtils.d(TAG, "onEvent RecordChanged:isRecord=" + event.getRecording());
                    LogUtils.d(TAG, "onEvent RecordChanged:path=" + event.getRecordPath());
                    break;
            }
        });
    }

    /**
     * 设置状态
     *
     * @param newState
     */
    private void setState(int newState) {
        if (currentState == newState) return;
        int oldState = currentState;
        currentState = newState;
        if (playListener != null) {
            mainHandler.post(() -> playListener.onPlayStatusChange(newState));
        }
    }

    @Override
    public void setVideoTextureView(@Nullable TextureView textureView) {
        this.textureView = textureView;
        _bindVideoSurface();
    }

    private void _bindVideoSurface() {
        if (textureView == null) return;
        if (mediaPlayer != null) {
            setVideoSurface(textureView.getSurfaceTexture());
            setWindowSize(textureView.getWidth(), textureView.getHeight());
            textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
                @Override
                public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                    LogUtils.d(TAG, "onSurfaceTextureAvailable");
                    setVideoSurface(surface);
                    setWindowSize(width, height);

                }

                @Override
                public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

                }

                @Override
                public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                    mediaPlayer.getVLCVout().detachViews();
                    return false;
                }

                @Override
                public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

                }
            });
            textureView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                // 获取新的宽度和高度
                int w = right - left;
                int h = bottom - top;
                setWindowSize(w, h);
            });
        }
    }

    private void setVideoSurface(SurfaceTexture surfaceTexture) {
        if (surfaceTexture == null) {
            return;
        }
        LogUtils.d(TAG, "setVideoSurface:");
//        mediaPlayer.getVLCVout().setVideoSurface(surfaceTexture);
//        mediaPlayer.getVLCVout().attachViews();
        Surface surface = new Surface(surfaceTexture);
        IVLCVout vlcVout = mediaPlayer.getVLCVout();
        vlcVout.setVideoSurface(surface, null);
        vlcVout.attachViews();

    }

    /**
     * 设置播放窗口大小
     *
     * @param width
     * @param height
     */
    public void setWindowSize(int width, int height) {
        // 设置VLC播放器的宽高参数
        if (width > 0 && height > 0) {
            mediaPlayer.getVLCVout().setWindowSize(width, height);
            //下面2行代码 设置充满屏幕否则有黑边
            mediaPlayer.setAspectRatio(width + ":" + width);
            mediaPlayer.setScale(0);
        }
        LogUtils.d(TAG, "Window width=" + width + ",width=" + height);

    }

    @Override
    public void setPlayUrl(@Nullable String url) {
        mPlayUrl = url;
    }

    @Override
    public void prepare() {

    }

    @Override
    public void play() {
        if (!isPlaying()) {
            sendOption(OP_PLAY);
        }
    }


    @Override
    public void pause() {
        sendOption(OP_PAUSE);
    }

    @Override
    public void stop() {
        sendOption(OP_STOP);
    }

    @Override
    public void release() {
        sendOption(OP_RELEASE);
    }

    @Override
    public boolean isPlaying() {
        return mediaPlayer != null && mediaPlayer.isPlaying();
    }


    @Override
    public int getState() {
        return currentState;
    }

    @Override
    public long getCurrentPosition() {
        return mediaPlayer != null ? mediaPlayer.getTime() : 0;
    }

    @Override
    public long getDuration() {
        return mediaPlayer != null ? mediaPlayer.getLength() : 0;
    }

    @Override
    public boolean isSeekable() {
        return mediaPlayer != null && mediaPlayer.isSeekable();
    }

    @Override
    public void seekTo(long time) {
        if (isSeekable()) {
            mediaPlayer.setTime(time);
        }
    }

    @Override
    public void setMute(boolean mute) {
        this.mute = mute;
        if (mediaPlayer != null) {
            mediaPlayer.setVolume(mute ? 0 : 100);
        }
    }

    @Override
    public boolean isMute() {
        return mute;
    }

    @Override
    public Bitmap captureBitmap() {
        if (isPlaying() && textureView != null) {
            return textureView.getBitmap();
        }
        return null;
    }

    @Override
    public void capturePictureToFile(@NonNull String path) {
        Bitmap bitmap = captureBitmap();
        if (bitmap == null && capturePictureListener != null) {
            //截图失败
            ThreadUtils.runMainThread(() -> {
                if (capturePictureListener != null) {
                    capturePictureListener.onCapturePictureResult(false, null, path);
                }
            });
            return;
        }
        if (bitmap != null) {
            //截图成功
            ThreadUtils.getExecutorService().execute(() -> {
                boolean success = Utils.keepBitmap(bitmap, 100, path);
                ThreadUtils.runMainThread(() -> {
                    Utils.scannerFile(context, path);
                    if (capturePictureListener != null) {
                        capturePictureListener.onCapturePictureResult(true, bitmap, path);
                    }
                });
            });

        }

    }

    @Override
    public boolean isRecording() {
        return isRecording;
    }


    @Override
    public void startRecordVideo(String path) {
        if (isRecording || mediaPlayer == null || !isPlaying()) return;
        recordPath = path;
        isRecording = true;
        new Thread(() -> {
            try {
                TIME_PRINTER.start("正在启动录像");
                isRecording = mediaPlayer.record(path);
                TIME_PRINTER.print("启动录像:" + (isRecording ? "成功" : "失败"));
                if (videoRecordListener != null) {
                    mainHandler.post(() -> {
                        if (videoRecordListener != null) {
                            if (isRecording) {
                                videoRecordListener.onStartRecordVideo();
                            } else {
                                videoRecordListener.onErrorRecordVideo("启动录像失败");
                            }
                        }
                    });
                }
            } catch (Exception e) {
                TIME_PRINTER.print("启动录像失败");
                recordPath = null;
                isRecording = false;
                LogUtils.e(TAG, "启动录像失败:" + e.getMessage());
                if (videoRecordListener != null) {
                    mainHandler.post(() -> {
                        if (videoRecordListener != null) {
                            videoRecordListener.onErrorRecordVideo(e.getMessage());
                        }
                    });
                }
            }
        }).start();
    }

    @Override
    public void stopRecordVideo() {
        if (!isRecording || mediaPlayer == null) return;
        isRecording = false;
        backgroundHandler.post(() -> {
            try {
                TIME_PRINTER.start("正在停止录像");
                mediaPlayer.record(null);
                TIME_PRINTER.print("停止录像");
                final String path = recordPath;
                if (videoRecordListener != null) {
                    mainHandler.post(() -> {
                        if (videoRecordListener != null) {
                            videoRecordListener.onStopRecordVideo(path);
                        }
                    });
                }

            } catch (Exception e) {
                TIME_PRINTER.print("停止录像失败");
                LogUtils.e(TAG, "停止录像失败:" + e.getMessage());
                if (videoRecordListener != null) {
                    mainHandler.post(() -> {
                        if (videoRecordListener != null) {
                            videoRecordListener.onErrorRecordVideo(e.getMessage());
                        }
                    });
                }
            }

        });
    }

    @Override
    public void setPlayListener(@Nullable Listener playListener) {
        this.playListener = playListener;
    }

    @Override
    public void setCapturePictureListener(@Nullable CapturePictureListener capturePictureListener) {
        this.capturePictureListener = capturePictureListener;
    }

    @Override
    public void setVideoRecordListener(@Nullable VideoRecordListener videoRecordListener) {
        this.videoRecordListener = videoRecordListener;
    }

    @Override
    public void setPlayProgressListener(@Nullable PlayProgressListener playProgressListener) {
        this.playProgressListener = playProgressListener;
//        if (playProgressListener != null) {
//            startProgressUpdates();
//        } else {
//            stopProgressUpdates();
//        }
    }


    /**
     * 开启播放进度更新
     */
    private void startProgressUpdates() {
        stopProgressUpdates();
        if (playProgressListener == null) return;
        mainHandler.postDelayed(progressUpdateRunnable, PROGRESS_UPDATE_INTERVAL);
    }

    /**
     * 停止播放进度更新
     */
    private void stopProgressUpdates() {
        mainHandler.removeCallbacks(progressUpdateRunnable);
    }

    /**
     * 播放进度更新任务
     */
    private final Runnable progressUpdateRunnable = new Runnable() {
        @Override
        public void run() {
            if (playProgressListener != null && mediaPlayer != null && currentState == PLAYING) {
                long position = getCurrentPosition();
                long duration = getDuration();
                playProgressListener.onPositionChange(position);
                playProgressListener.onDurationChange(duration);
            }
            mainHandler.postDelayed(this, PROGRESS_UPDATE_INTERVAL);
        }
    };

    /**
     * 错误回掉
     *
     * @param code 错误代码
     */
    private void notifyError(int code) {
        notifyError(code, null);
    }

    /**
     * 错误回掉
     *
     * @param code       错误代码
     * @param privateMsg 错误信息
     */
    private void notifyError(int code, String privateMsg) {
        String errorMessage = PlayError.getErrorMessage(code);
        if (TextUtils.isEmpty(privateMsg)) {
            LogUtils.e(TAG, MessageFormat.format("Error: code:{0},msg:{1}", code, errorMessage));
        } else {
            LogUtils.e(TAG, MessageFormat.format("Error: code:{0},msg:{1}:{2}", code, errorMessage, privateMsg));
        }
        if (playListener != null) {
            mainHandler.post(() -> {
                if (playListener != null) {
                    playListener.onPlayError(code, errorMessage);
                }
            });
        }
    }

    private static class TimePrinter {
        private long _startTime;

        public void start() {
            start(null);
        }

        public void start(String msg) {
            _startTime = System.currentTimeMillis();
            if (msg != null) {
                LogUtils.d(TAG, msg);
            }
        }

        public void print(String tag) {
            float times = (System.currentTimeMillis() - _startTime) / 1000f;
            LogUtils.d(TAG, String.format(Locale.CHINA, "%s,耗时:%2f", tag, times));
        }
    }


}
